#include "config.h"

#include <sys/mman.h>
#include <sys/statvfs.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sendfile.h>
#include <unistd.h>
#include <netdb.h>
#include <time.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/vfs.h>
#include <ustat.h>
#include <openssl/sha.h>
#include <stdarg.h>
#include <ctype.h>
#include <sys/wait.h>
#include <dirent.h>
#include <libaio.h>
#include <sys/file.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/syscall.h>
#include <libgen.h>
#include <execinfo.h>
#include <linux/fs.h>

#define DBG_SUBSYS S_LIBYLIB

#include "sysy_conf.h"
#include "sysutil.h"
#include "configure.h"
#include "adt.h"
#include "yid.h"
#include "base64_urlsafe.h"
#include "sysy_lib.h"
#include "schedule.h"
#include "analysis.h"
#include "etcd-api.h"
#include "etcd.h"
#include "dbg.h"


#define __FASTRANDOM_SIZE__ (1024 * 10)

static __thread uint64_t *__random_private__ = NULL;
static __thread int __idx_private__;

static uint64_t *__random__ = NULL;
static int __idx__;

static uint64_t *__fastrandom_create()
{
        int ret, i;
        uint64_t *rand;

        ANALYSIS_BEGIN(0);
        ret = ymalloc((void**)&rand, sizeof(*rand) * __FASTRANDOM_SIZE__);
        if (ret)
                GOTO(err_ret, ret);

        for (i = 0; i < __FASTRANDOM_SIZE__; i++) {
                rand[i] = _random();
        }

        ANALYSIS_END(0, 1000 * 100, NULL);

        DINFO("create fast random size %ju\n", sizeof(*rand) * __FASTRANDOM_SIZE__);

        return rand;
err_ret:
        return NULL;
}

int fastrandom_init()
{
        int ret;

        __random__ = __fastrandom_create();
        if (__random__ == NULL) {
                ret = ENOMEM;
                GOTO(err_ret, ret);
        }

        __idx__ = 0;

        return 0;
err_ret:
        return ret;
}

int fastrandom_private_init()
{
        int ret;

        __random_private__ = __fastrandom_create();
        if (__random__ == NULL) {
                ret = ENOMEM;
                GOTO(err_ret, ret);
        }

        __idx_private__ = 0;

        return 0;
err_ret:
        return ret;
}

static uint64_t __fastrandom(const uint64_t *rand, int *idx)
{
        uint64_t res;

        res = rand[*idx];
        *idx = (*idx + 1) % __FASTRANDOM_SIZE__;

        DBUG("rand %ju\n", res);
        
        return res;
}

uint64_t fastrandom()
{
        if (__random_private__)
                return __fastrandom(__random_private__, &__idx_private__);
        else
                return __fastrandom(__random__, &__idx__);
}
